package service

import (
	"bytes"
	"context"
	"errors"
	"gitee.com/Frank098/container-management/model"
	"gitee.com/Frank098/container-management/utils"
	"io"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/kubernetes/scheme"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/tools/remotecommand"
	"sigs.k8s.io/yaml"
	"strings"
	"time"
)

var Pod pod

// PodsResp 定义列表的返回内容,Items是pod元素列表,Total是元素数量
type PodsResp struct {
	Total int          `json:"total"`
	Items []corev1.Pod `json:"items"`
}
type pod struct{}

type PtyHandler interface {
	io.Reader
	io.Writer
	remotecommand.TerminalSizeQueue
}

func (p *pod) GetDetail(podName string, namespace string) (pod *corev1.Pod, err error) {
	pod, err = K8s.ClientSet.CoreV1().Pods(namespace).Get(context.TODO(), podName, metav1.GetOptions{})
	if err != nil {
		return nil, errors.New("获取Pod详情失败," + err.Error())
	}
	return pod, nil
}

func (p *pod) DeletePod(podName string, namespace string) (err error) {
	err = K8s.ClientSet.CoreV1().Pods(namespace).Delete(context.TODO(), podName, metav1.DeleteOptions{})
	if err != nil {
		return errors.New("删除Pod详情失败," + err.Error())
	}
	return nil
}

func (p *pod) GetPodInfo(podName string, namespace string) (pod *corev1.Pod, err error) {
	pod, err = K8s.ClientSet.CoreV1().Pods(namespace).Get(context.TODO(), podName, metav1.GetOptions{})
	if err != nil {
		return nil, errors.New("获取Pod详情失败," + err.Error())
	}
	return pod, nil
}

// GetPodLog 获取Pod内容器日志
func (p *pod) GetPodLog(containerName, podName, namespace string, follow bool, tailLine int64, previous bool) (podlog string, err error) {
	//Container:容器名称
	//Follow:跟踪Pod的日志流，默认为false（关闭）对应kubectl logs命令中的 -f 参数
	//TailLines:如果设置，则显示从日志末尾开始的行数。如果未指定，则从容器的创建开始或从秒开始或从时间开始显示日志
	//Previous:返回以前终止的容器日志。默认为false（关闭）
	option := &corev1.PodLogOptions{
		Container: containerName,
		Follow:    follow,
		TailLines: &tailLine,
		Previous:  previous,
	}
	req := K8s.ClientSet.CoreV1().Pods(namespace).GetLogs(podName, option)

	// 发起stream连接,获取到Response.body
	podLogs, err := req.Stream(context.TODO())
	if err != nil {
		return "", errors.New("获取pod日志失败," + err.Error())
	}
	defer podLogs.Close()
	// 将Response.body 写入到缓存区,目的为了转换成string类型
	buf := new(bytes.Buffer)
	_, err = io.Copy(buf, podLogs)
	if err != nil {
		return "", errors.New("pod日志写入缓存区失败," + err.Error())
	}
	return buf.String(), nil
}

func (p *pod) GetPodAllPerNp() (podsNps []*model.PodsNp, err error) {
	//获取namespace列表
	namespaceList, err := K8s.ClientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, errors.New("获取命名空间列表失败," + err.Error())
	}
	for _, namespace := range namespaceList.Items {
		//获取pod列表
		podsNp, err := p.GetPodSingleNp(namespace.Name)
		if err != nil {
			return nil, errors.New("获取pod列表失败," + err.Error())
		}

		podsNps = append(podsNps, podsNp...)
	}
	return podsNps, nil
}

// GetPodSingleNp 获取单个namespace中pod的数量
func (p *pod) GetPodSingleNp(namespace string) (podsNps []*model.PodsNp, err error) {
	podList, err := K8s.ClientSet.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, errors.New("获取pod列表失败," + err.Error())
	}
	for _, podListInfo := range podList.Items {
		//组装数据
		currentContainerTime := podListInfo.CreationTimestamp
		dateOfDifference := utils.SubDays(time.Now(), currentContainerTime.Time)
		podMetricses, err := K8s.Mc.MetricsV1beta1().PodMetricses(namespace).Get(context.TODO(), podListInfo.Name, metav1.GetOptions{})
		if err != nil {
			return nil, errors.New("获取pod指标失败," + err.Error())
		}
		//组装数据
		podsNp := &model.PodsNp{
			Namespace: namespace,
			PodConventionInfo: &model.PodConventionInfo{
				Status:       string(podListInfo.Status.Phase),
				Name:         podListInfo.Name,
				Image:        podListInfo.Spec.Containers[0].Image,
				Age:          dateOfDifference,
				RestartCount: int(podListInfo.Status.ContainerStatuses[0].RestartCount),
				PodIp:        podListInfo.Status.PodIP,
				NodeName:     podListInfo.Spec.NodeName,
				Cpu:          podMetricses.Containers[0].Usage.Cpu().String(),
				Memory:       podMetricses.Containers[0].Usage.Memory().String(),
			},
		}
		//添加到podsNps数组中
		podsNps = append(podsNps, podsNp)
	}
	return podsNps, nil
}

func (p *pod) PodCmdExec(config *restclient.Config, podName, namespace, cmd string) (map[string]string, error) {

	// 构造执行命令请求
	req := K8s.ClientSet.CoreV1().RESTClient().Post().
		Resource("pods").
		Name(podName).
		Namespace(namespace).
		SubResource("exec").
		VersionedParams(&corev1.PodExecOptions{
			Command: []string{"sh", "-c", cmd},
			Stdin:   true,
			Stdout:  true,
			Stderr:  true,
			TTY:     false,
		}, scheme.ParameterCodec)
	// 执行命令
	executor, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
	if err != nil {
		return nil, err
	}
	// 使用bytes.Buffer变量接收标准输出和标准错误
	var stdout, stderr bytes.Buffer
	if err = executor.StreamWithContext(context.TODO(), remotecommand.StreamOptions{
		Stdin:  strings.NewReader(""),
		Stdout: &stdout,
		Stderr: &stderr,
	}); err != nil {
		return nil, err
	}
	// 返回数据
	ret := map[string]string{"stdout": stdout.String(), "stderr": stderr.String(), "pod_name": podName}
	return ret, nil
}

func (p *pod) GetPodYaml(podName, namespace string) (podYaml *model.PodYamlResponse, err error) {
	podYamlInfo, err := K8s.ClientSet.CoreV1().Pods(namespace).Get(context.Background(), podName, metav1.GetOptions{})
	if err != nil {
		return nil, errors.New("获取pod编排文件失败," + err.Error())
	}
	podYamlInfo.ManagedFields = []metav1.ManagedFieldsEntry{}
	podYamlInfo.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
		Kind:    "Pod",
		Version: "v1",
	})
	// 将对象解析为yaml，返回[]byte 和err错误信息
	podYamlByte, err := yaml.Marshal(podYamlInfo)
	if err != nil {
		return nil, errors.New("对象解析为yaml失败," + err.Error())
	}
	podYaml = &model.PodYamlResponse{
		PodYaml: string(podYamlByte),
	}
	return podYaml, nil
}
